/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package mapmakerapp;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.xml.parsers.*;

import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.w3c.dom.*;


/**
 *
 * @author Administrator
 */
public class MyFrame extends JFrame
{
    MapPanel panel;
    JMenuBar menuBar;
    JMenuItem menuItemLoad;
    JMenuItem menuItemSave;
    JMenuItem menuItemCloseMap;

    private String pathFileSave = "";
    
    public MyFrame()
    {
        super();
        
    }

    public void initFrame()
    {
        this.setSize(500, 500);
        this.setResizable(false);
        this.setBackground(Color.BLACK);
        setLocationRelativeTo(null);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        //create custom close operation
        addWindowListener(new WindowAdapter()
        {
            @Override
            public void windowClosing(WindowEvent e)
            {
                exitProcedure();
            }
        });

        panel = new MapPanel(this);
        panel.setBackground(Color.CYAN);
        this.add(panel, BorderLayout.CENTER);

        addMenuBar();
    }

    private void addMenuBar()
    {
        // Create the menu bar
        menuBar = new JMenuBar();
        JMenu menuFile = new JMenu("File");
        JMenu menuEdit = new JMenu("Edit");
        JMenu menuTool = new JMenu("Tools");
        
        menuBar.add(menuFile);
        menuBar.add(menuEdit);
        menuBar.add(menuTool);

        JCheckBoxMenuItem itemUseBound = new JCheckBoxMenuItem("Use Bound");
        itemUseBound.setSelected(true);
        itemUseBound.addActionListener(actionUseBound);
        menuEdit.add(itemUseBound);
        
        JMenuItem item = new JMenuItem("Load BackGround");
        item.addActionListener(actionLoadBG);
        menuEdit.add(item);

        menuItemLoad = new JMenuItem("Load An Item");
        menuItemLoad.addActionListener(actionLoadItem);
        menuItemLoad.setEnabled(false);
        menuItemLoad.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_L, java.awt.Event.CTRL_MASK));
        menuEdit.add(menuItemLoad);

        JMenuItem item1 = new JMenuItem("Open");
        item1.addActionListener(actionOpen);
        item1.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.Event.CTRL_MASK));
        menuFile.add(item1);
        
        menuItemSave = new JMenuItem("Save");
        menuItemSave.setEnabled(false);
        menuItemSave.addActionListener(actionSave);
        menuItemSave.setAccelerator(KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.Event.CTRL_MASK));
        menuFile.add(menuItemSave);

        menuItemCloseMap = new JMenuItem("Close Map");
        menuItemCloseMap.setEnabled(false);
        menuItemCloseMap.addActionListener(actionCloseMap);
        menuFile.add(menuItemCloseMap);
        
        JMenuItem item2 = new JMenuItem("Exit");
        item2.addActionListener(actionExit);
        menuFile.add(item2);

        JMenuItem itemPackage = new JMenuItem("Package map");
        itemPackage.addActionListener(actionPackage);
        menuTool.add(itemPackage);
        
        this.setJMenuBar(menuBar);
    }

    // ---
    private void loadBackground() {
        try {
            //System.out.println("loading background ...");
            String filename = File.separator + "tmp";
            JFileChooser fc = new JFileChooser(new File(filename));            
            
            fc.showOpenDialog(this);
            File selFile = fc.getSelectedFile();            

            if(selFile != null)
            {               
                boolean isSucc = panel.setItem(0, selFile.getAbsolutePath(), "", "", 0, 0, 0, 0, 1);
                if(isSucc)
                {                    
                    setLocationRelativeTo(null);
                    
                    menuItemLoad.setEnabled(true);
                    menuItemSave.setEnabled(true);
                    menuItemCloseMap.setEnabled(true);
                    invalidate();
                }
            }            
            //System.out.println("loading background done");
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private void loadItem()
    {
        try {
            //System.out.println("loading item ...");
            String filename = File.separator + "tmp";
            JFileChooser fc = new JFileChooser(new File(filename));          

            fc.showOpenDialog(this);
            File selFile = fc.getSelectedFile();            

            if(selFile != null)
            {                
                panel.setItem(panel.getCountItems(), selFile.getAbsolutePath(), "", "", 0, 0, 0, 0, 1);
            }
            //System.out.println("loading item done!");
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    
    // ---
    public Dimension getInsetDimension()
    {
        Insets insets = getInsets();
        int insetwidth = insets.left + insets.right;
        int insetheight = insets.top + insets.bottom + menuBar.getHeight();// + menuBar.getInsets().top +  menuBar.getInsets().bottom;

        //System.out.println("menu bar:" + menuBar.getInsets().top + "-" +  menuBar.getInsets().bottom);
        return new Dimension(insetwidth, insetheight);
    }

     private void exitProcedure()
     {
        //System.out.println("doing exit");
        // -- save map
        saveMap();
     }

     private void exit()
     {
         dispose();
     }

     private void saveMap()
     {
        try {
            if(panel.getCountItems() == 0)
                return;
            
            if(pathFileSave.equals(""))
            {
                String filename = File.separator + "tmp";
                JFileChooser fc = new JFileChooser(new File(filename));
                // Show save dialog; this method does not return until the dialog is closed
                fc.showSaveDialog(this);
                File selFile = fc.getSelectedFile();
                //System.out.println("saved file:" + selFile.getAbsolutePath());

                if(selFile != null)
                {
                    pathFileSave = selFile.getAbsolutePath();
                    this.setTitle(selFile.getName());
                }
                else
                    return;
            }
            /////////////////////////////
            //Creating an empty XML Document
            //We need a Document
            DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
            Document doc = (Document) docBuilder.newDocument();

            ////////////////////////
            //Creating the XML tree
            //create the root element and add it to the document
            Element root = (Element)doc.createElement("map");
            doc.appendChild(root);

            //create a comment and put it in the root element
            //Comment comment = doc.createComment("Just a thought");
            //root.appendChild(comment);
            MapItem backgroundItem = panel.getMapItem(0);
            Element background = doc.createElement("background");
            
            Element path = doc.createElement("path");
            path.appendChild(doc.createTextNode(backgroundItem.path));
            background.appendChild(path);
            Element name = doc.createElement("name");
            name.appendChild(doc.createTextNode(backgroundItem.name));
            background.appendChild(name);
            
            root.appendChild(background);

            String id = "";
            MapItem mapItem;
            Element desc, objectName, x, y, flip, rotate, scale;
            
            for(int i=1; i<panel.getCountItems(); i++)
            {
                mapItem = panel.getMapItem(i);
                Element item = doc.createElement("item");
                id = String.valueOf(i-1);
                item.setAttribute("id", id);

                path = doc.createElement("path");
                path.appendChild(doc.createTextNode(mapItem.path));
                item.appendChild(path);
                
                name = doc.createElement("name");
                name.appendChild(doc.createTextNode(mapItem.name));
                item.appendChild(name);

                desc = doc.createElement("desc");
                desc.appendChild(doc.createTextNode(mapItem.desc));
                item.appendChild(desc);

                objectName = doc.createElement("objectName");
                objectName.appendChild(doc.createTextNode(mapItem.objectName));
                item.appendChild(objectName);
                
                x = doc.createElement("x");
                x.appendChild(doc.createTextNode(String.valueOf(mapItem.topleft.x)));
                item.appendChild(x);

                y = doc.createElement("y");
                y.appendChild(doc.createTextNode(String.valueOf(mapItem.topleft.y)));
                item.appendChild(y);

                flip = doc.createElement("flip");
                flip.appendChild(doc.createTextNode(String.valueOf(mapItem.flip)));
                item.appendChild(flip);

                rotate = doc.createElement("rotate");
                rotate.appendChild(doc.createTextNode(String.valueOf(mapItem.rotate)));
                item.appendChild(rotate);

                scale = doc.createElement("scale");
                scale.appendChild(doc.createTextNode(String.valueOf(mapItem.scale)));
                item.appendChild(scale);

                root.appendChild(item);
            }           
            /////////////////
            //Output the XML
            //set up a transformer
            TransformerFactory transfac = TransformerFactory.newInstance();
            Transformer trans = transfac.newTransformer();
            trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            trans.setOutputProperty(OutputKeys.INDENT, "yes");

            //create file from xml tree            
            File f=new File(pathFileSave);
            if(f.exists())
                f.delete();
            f.createNewFile();
              
            StreamResult result = new StreamResult(f);
            DOMSource source = new DOMSource(doc);
            trans.transform(source, result);            
        }
        catch (Exception e) {
            System.out.println(e);
        }
         
     }
    
     private boolean openMap()
     {
         try
         {
            String filename = File.separator + "tmp";
            JFileChooser fc = new JFileChooser(new File(filename));
            
            fc.showOpenDialog(this);
            File selFile = fc.getSelectedFile();
            //System.out.println(selFile.getAbsolutePath());

            if(selFile == null)
            {
                return false;
            }            
                    
            String path, desc, objectName;
            int x, y, flip, rotate;
            float scale;
            boolean isSucc;

            pathFileSave = selFile.getAbsolutePath();
            
              DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
              DocumentBuilder db = dbf.newDocumentBuilder();
              Document doc = db.parse(selFile);
              doc.getDocumentElement().normalize();
              //System.out.println("Root element " + doc.getDocumentElement().getNodeName());
              
              NodeList bgNodes = doc.getElementsByTagName("background");              
              if(bgNodes.getLength() > 0)
              {
                  Node fstNode = bgNodes.item(0);
                  if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
                      Element bgElmnt = (Element) fstNode;                      
                      path = getNodeValue(bgElmnt, "path");
                      //System.out.println("paht:" + path);

                      panel.deleteMap();
                      isSucc = panel.setItem(0, path, "", "", 0, 0, 0, 0, 1);
                      if(!isSucc)
                          return false;
                  }
              }
              else
                  return false;

              NodeList itemNodes = doc.getElementsByTagName("item");
              int count = itemNodes.getLength();
              for(int i=0; i < count; i++)
              {
                  Node fstNode = itemNodes.item(i);
                  if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
                      Element itemElmnt = (Element) fstNode;                      
                      path = getNodeValue(itemElmnt, "path");
                      desc = getNodeValue(itemElmnt, "desc");
                      objectName = getNodeValue(itemElmnt, "objectName");

                      x = Integer.valueOf(getNodeValue(itemElmnt, "x"));
                      y = Integer.valueOf(getNodeValue(itemElmnt, "y"));
                      flip = Integer.valueOf(getNodeValue(itemElmnt, "flip"));
                      rotate = Integer.valueOf(getNodeValue(itemElmnt, "rotate"));
                      scale = Float.valueOf(getNodeValue(itemElmnt, "scale"));

                      isSucc = panel.setItem(i + 1, path, desc, objectName, x, y, flip, rotate, scale);
                      if(!isSucc)
                          return false;
                  }
              }

              pathFileSave = selFile.getAbsolutePath();
              this.setTitle(selFile.getName());
         }
         catch(Exception e)
         {
             e.printStackTrace();
             return false;
         }

         return true;
     }

     private boolean closeMap()
     {
        try
        {
            pathFileSave = "";
            setTitle(pathFileSave);

            panel.deleteMap();
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
            return false;
        }

        return true;
     }

     private void packageMap()
     {
        try
        {
            saveMap();

            if(pathFileSave.equals(""))
            {
                JOptionPane.showMessageDialog(this, "Package map failed!", "Fail", JOptionPane.OK_OPTION);
                return;
            }

            JFileChooser fc = new JFileChooser();
            fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
            if (JFileChooser.APPROVE_OPTION == fc.showSaveDialog(this))
            {
                File file = fc.getSelectedFile();

                if(file != null && file.isDirectory())
                {
                    //System.out.println("folder:" + file.getAbsolutePath());
                    String nameMap = getMapName();
                    //System.out.println("folder:" + nameMap);

                    File destDir = new File(file, nameMap);

                    if(destDir.exists())
                        if(destDir.isDirectory())
                            destDir.delete();

                    destDir.mkdir();
                    // copy map.xml
                    copy2Dir(pathFileSave, destDir);

                    // copy background and image item
                    for(int i=0; i<panel.getCountItems();i++)
                    {
                        MapItem item = panel.getMapItem(i);
                        copy2Dir(item.path, destDir);
                    }
                }
            }
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
            return ;
        }
     }

     private void copy2Dir(String pathFileSrc, File destDir)
     {            
            int index = pathFileSrc.lastIndexOf("\\");
            if(index < 0)
                index = pathFileSrc.lastIndexOf("/");

            String fileName = pathFileSrc.substring(index + 1, pathFileSrc.length());

            File fromFile = new File(pathFileSrc);
            File toFile = new File(destDir, fileName);

            FileInputStream from = null;
            FileOutputStream to = null;
            try {
                  from = new FileInputStream(fromFile);
                  to = new FileOutputStream(toFile);
                  byte[] buffer = new byte[4096];
                  int bytesRead;

                  while ((bytesRead = from.read(buffer)) != -1)
                    to.write(buffer, 0, bytesRead); // write
            } 
            catch(Exception ex)
            {
                ex.printStackTrace();
            }
            finally
            {
                  if (from != null)
                    try {
                      from.close();
                    } catch (IOException e) {

                    }
                  if (to != null)
                    try {
                      to.close();
                    } catch (IOException e) {

                    }
            }
     }
     
     private String getMapName()
     {
            if(pathFileSave.equals(""))
                return "";

            int index = pathFileSave.lastIndexOf("\\");
            if(index < 0)
                index = pathFileSave.lastIndexOf("/");

            String fileName = pathFileSave.substring(index + 1, pathFileSave.length());
            index = fileName.lastIndexOf(".");

            String name = fileName.substring(0,index);
            return name;
     }

     public String getPathFileSave()
     {
         return pathFileSave;
     }
     
     private String getNodeValue(Element E, String tag)
     {
         try
         {
            NodeList tagElmnt = E.getElementsByTagName(tag);
            Element fstTagElmnt = (Element) tagElmnt.item(0);
            NodeList fstNm;
            
            if(fstTagElmnt != null)
                fstNm = fstTagElmnt.getChildNodes();
            else
                return "";

            if(fstNm != null && fstNm.getLength() > 0)
                return ((Node)fstNm.item(0)).getNodeValue();
            else
                return "";
         }
         catch(Exception ex)
         {
             return "";
         }
     }
          
     // The action
    public Action actionLoadBG = new AbstractAction("Load BG") {
        public void actionPerformed(ActionEvent evt) {
            // Perform action
            loadBackground();
            panel.updateUI();
        }
    };

    public Action actionExit = new AbstractAction("Exit") {
        public void actionPerformed(ActionEvent evt) {
            // Perform action
            exitProcedure();
            exit();
        }
    };

    public Action actionLoadItem = new AbstractAction("Load Item") {
        public void actionPerformed(ActionEvent evt) {
            // Perform action
            loadItem();
            panel.updateUI();
        }
    };

    public Action actionUseBound = new AbstractAction("Use Bound") {
        public void actionPerformed(ActionEvent evt) {
            // Perform action
            AbstractButton aButton = (AbstractButton) evt.getSource();
            boolean selected = aButton.getModel().isSelected();
        
            panel.useBound = selected;
            panel.updateUI();
        }
    };

    public Action actionSave = new AbstractAction("Save") {
        public void actionPerformed(ActionEvent evt) {
            // Perform action
            saveMap();
        }
    };

    public Action actionOpen = new AbstractAction("Open") {
        public void actionPerformed(ActionEvent evt) {
            // Perform action
            saveMap();
            boolean isSuccc = openMap();

            if(isSuccc)
            {                
                menuItemLoad.setEnabled(true);
                menuItemSave.setEnabled(true);
                menuItemCloseMap.setEnabled(true);
                
                setLocationRelativeTo(null);                
                invalidate();
                panel.updateUI();
            }
            else
            {
                pathFileSave = "";
                panel.deleteMap();
                menuItemLoad.setEnabled(!true);
                menuItemSave.setEnabled(!true);
                menuItemCloseMap.setEnabled(!true);
                
                JOptionPane.showMessageDialog(panel.getParent(), "Open map failed!", "Fail", JOptionPane.OK_OPTION);
                setLocationRelativeTo(null);
                invalidate();
                panel.updateUI();
            }
        }
    };

    public Action actionCloseMap = new AbstractAction("Close Map") {
        public void actionPerformed(ActionEvent evt) {
            // Perform action
            saveMap();
            boolean isSuccc = closeMap();

            if(isSuccc)
            {
                menuItemLoad.setEnabled(false);
                menuItemSave.setEnabled(false);
                menuItemCloseMap.setEnabled(false);

                setLocationRelativeTo(null);
                invalidate();
                panel.updateUI();
            }          
        }
    };

    public Action actionPackage = new AbstractAction("Package Map") {
        public void actionPerformed(ActionEvent evt) {
            // Perform action
            packageMap();            
        }
    };
}
